home *** CD-ROM | disk | FTP | other *** search
/ Qu.......ke Neue Level / KroGer Software GmbH - Qu_ke.iso / UTILITY / PRG8.ZIP / F_SPRITE.C < prev    next >
C/C++ Source or Header  |  1996-03-03  |  14KB  |  473 lines

  1. /*
  2.  * Copyright (C) 1996 by Raphael Quinet.  All rights reserved.
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and
  5.  * its documentation for any purpose and without fee is hereby
  6.  * granted, provided that the above copyright notice appear in all
  7.  * copies and that both that copyright notice and this permission
  8.  * notice appear in supporting documentation.  If more than a few
  9.  * lines of this code are used in a program which displays a copyright
  10.  * notice or credit notice, the following acknowledgment must also be
  11.  * displayed on the same screen: "This product includes software
  12.  * developed by Raphael Quinet for use in the Quake Editing Utilities
  13.  * project."  THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR
  14.  * IMPLIED WARRANTY.
  15.  *
  16.  * More information about the QEU project can be found on the WWW:
  17.  * "http://www.montefiore.ulg.ac.be/~quinet/games/editing.html" or by
  18.  * mail: Raphael Quinet, 9 rue des Martyrs, B-4550 Nandrin, Belgium.
  19.  */
  20.  
  21. /*
  22.  * F_SPRITE.C - Read and write Quake sprite files.
  23.  */
  24.  
  25. /*
  26.  * NOTE: There are still some parts of the sprite format which are a
  27.  *       bit strange for me.  I could be wrong for the multi-image
  28.  *       stuff, even if it works rather well.  The test version of
  29.  *       Quake doesn't contain enough "special" sprites like the
  30.  *       torches (s_torch*.spr) and the shots (shots.spr), so I'm
  31.  *       not sure if my guesses are correct.
  32.  *       This piece of code is probably more complex than it should
  33.  *       be, but at least it works.  More or less.
  34.  */
  35.  
  36. #include "qeu.h"
  37. #include "q_misc.h"
  38. #include "q_files.h"
  39. #include "f_sprite.h"
  40. /*! #include <math.h> */
  41.  
  42. /*
  43.  * Create a new, empty sprite.
  44.  */
  45. SpritePtr NewSprite()
  46. {
  47.   SpritePtr sprite;
  48.  
  49.   sprite = (SpritePtr)QMalloc((UInt32)sizeof(struct SpriteInfo));
  50.   sprite->unknown1 = 0L;
  51.   sprite->unknown2 = 0L;
  52.   sprite->radius = 0.0;
  53.   sprite->maxwidth = 0;
  54.   sprite->maxheight = 0;
  55.   sprite->numframes = 0;
  56.   sprite->frames = NULL;
  57.   sprite->unknown4 = 0L;
  58.   sprite->unknown5 = 0L;
  59.   return sprite;
  60. }
  61.  
  62.  
  63. /*
  64.  * Discard a sprite and free memory.
  65.  */
  66. void FreeSprite(SpritePtr sprite)
  67. {
  68.   UInt16 i, j;
  69.  
  70.   if (sprite->numframes > 0)
  71.     for (i = 0; i < sprite->numframes; i++)
  72.       if (sprite->frames[i].images != NULL)
  73.     {
  74.       if (sprite->frames[i].numimages == 0)
  75.         {
  76.           if (sprite->frames[i].images[0].bitmap.data != NULL)
  77.         QFree(sprite->frames[i].images[0].bitmap.data);
  78.         }
  79.       else
  80.         {
  81.           for (j = 0; j < sprite->frames[i].numimages; j++)
  82.         if (sprite->frames[i].images[j].bitmap.data != NULL)
  83.           QFree(sprite->frames[i].images[j].bitmap.data);
  84.         }
  85.     }
  86.   QFree(sprite);
  87. }
  88.  
  89.  
  90. /*
  91.  * Add an image to a sprite.  The bitmap data is copied and can be
  92.  * freed after having called this function.  If "framenum" is negative
  93.  * and "multi" is FALSE, a new frame is created, containing a single
  94.  * image.  If "framenum" is negative and "multi" is TRUE, a new
  95.  * multi-image frame is created, using the value of "unknown" for the
  96.  * first image.  If "framenum" is greater or equal to zero and "multi"
  97.  * is TRUE, the image is added to an existing multi-image frame.
  98.  * Returns the number of the frame that was added or modified.
  99.  */
  100. UInt16 AddSpriteImage(SpritePtr sprite, Int16 framenum, Bool multi,
  101.               Float32 unknown, Int16 xoffset, Int16 yoffset,
  102.               BitMap *bmptr)
  103. {
  104.   UInt16 n, i;
  105.  
  106.   n = sprite->numframes;
  107.   if (framenum < 0)
  108.     {
  109.       if (n == 0)
  110.     sprite->frames = (SpriteFrame *)QMalloc((UInt32)sizeof(SpriteFrame));
  111.       else
  112.     sprite->frames = (SpriteFrame *)QRealloc(sprite->frames,
  113.                 (UInt32)(n + 1) * (UInt32)sizeof(SpriteFrame));
  114.       if (multi == TRUE)
  115.     {
  116.       sprite->frames[n].numimages = 1;
  117.       sprite->frames[n].unknown = (Float32 *)QMalloc(
  118.                               (UInt32)sizeof(Float32));
  119.     }
  120.       else
  121.     sprite->frames[n].numimages = 0;
  122.       sprite->frames[n].images = (SpriteImage *)QMalloc(
  123.                           (UInt32)sizeof(SpriteImage));
  124.       sprite->numframes = n + 1;
  125.       i = 0;
  126.     }
  127.   else
  128.     {
  129.       if (n == 0 || framenum >= n)
  130.     ProgError("BUG: cannot add an image to a non-existing frame (%d, %d)",
  131.           n, framenum);
  132.       n = framenum;
  133.       i = sprite->frames[n].numimages;
  134.       if (i == 0)
  135.     {
  136.       sprite->frames[n].unknown = (Float32 *)QMalloc(
  137.                               (UInt32)sizeof(Float32));
  138.       sprite->frames[n].images = (SpriteImage *)QMalloc(
  139.                           (UInt32)sizeof(SpriteImage));
  140.     }
  141.       else
  142.     {
  143.       sprite->frames[n].unknown = (Float32 *)QRealloc(
  144.                     sprite->frames[n].unknown, (UInt32)(i + 1)
  145.                             * (UInt32)sizeof(Float32));
  146.       sprite->frames[n].images = (SpriteImage *)QRealloc(
  147.                      sprite->frames[n].images, (UInt32)(i + 1)
  148.                         * (UInt32)sizeof(SpriteImage));
  149.     }
  150.       sprite->frames[n].unknown[i] = unknown;
  151.       sprite->frames[n].numimages = i + 1;
  152.     }
  153.   sprite->frames[n].images[i].xoffset = xoffset;
  154.   sprite->frames[n].images[i].yoffset = yoffset;
  155.   sprite->frames[n].images[i].bitmap.width = bmptr->width;
  156.   sprite->frames[n].images[i].bitmap.height = bmptr->height;
  157.   sprite->frames[n].images[i].bitmap.data = QMemDup(bmptr->data,
  158.                  (UInt32)(bmptr->width) * (UInt32)(bmptr->height));
  159.   return n;
  160. }
  161.  
  162.  
  163. /*
  164.  * Read a sprite into memory.  The optional offset to the start of the
  165.  * sprite data is given in "offset" (so that one can read the sprite
  166.  * data from an individual file as well as from within a WAD2 or PACK
  167.  * file).
  168.  */
  169. SpritePtr ReadSprite(FILE *file, UInt32 offset)
  170. {
  171.   SpritePtr sprite;
  172.   UInt32    numframes;
  173.   UInt16    n, i, f = 0;
  174.   UInt32    u, w, h;
  175.   Int32     x, y;
  176.   BitMap   *bmptr;
  177.   Float32  *unknown;
  178.  
  179.   if (file == NULL)
  180.     return NULL;
  181.   if ((fseek(file, offset, SEEK_SET) < 0)
  182.       || (ReadMagic(file) != FTYPE_SPRITE))
  183.     return NULL;
  184.   sprite = NewSprite();
  185.   if ((ReadInt32(file, &(sprite->unknown1)) == FALSE)
  186.       || (ReadInt32(file, &(sprite->unknown2)) == FALSE)
  187.       || (ReadFloat32(file, &(sprite->radius)) == FALSE)
  188.       || (ReadInt32(file, &w) == FALSE)
  189.       || (w > 65535L)
  190.       || (ReadInt32(file, &h) == FALSE)
  191.       || (h > 65535L)
  192.       || (ReadInt32(file, &numframes) == FALSE)
  193.       || (numframes > 65535L)
  194.       || (ReadInt32(file, &(sprite->unknown4)) == FALSE)
  195.       || (ReadInt32(file, &(sprite->unknown5)) == FALSE))
  196.     {
  197.       FreeSprite(sprite);
  198.       return NULL;
  199.     }
  200.   sprite->maxwidth = (UInt16)w;
  201.   sprite->maxheight = (UInt16)h;
  202.   if (numframes == 0L)
  203.     return sprite;
  204.   bmptr = NewBitMap();
  205.   bmptr->data = (UInt8 huge *)QMalloc(w * h);
  206.   for (n = 0; n < (UInt16)numframes; n++)
  207.     {
  208.       if (ReadInt32(file, &u) == FALSE)
  209.     {
  210.       FreeBitMap(bmptr);
  211.       FreeSprite(sprite);
  212.       return NULL;
  213.     }
  214.       if (u != 0)
  215.     {
  216. printf("(Frame %d) u = 0x%lx\n", n, u);
  217.       if (ReadInt32(file, &u) == FALSE)
  218.         {
  219.           FreeBitMap(bmptr);
  220.           FreeSprite(sprite);
  221.           return NULL;
  222.         }
  223.       unknown = (Float32 *)QMalloc(u * (UInt32)sizeof(Float32));
  224.       for (i = 0; i < (UInt16)u; i++)
  225.         if (ReadFloat32(file, &(unknown[i])) == FALSE)
  226.           {
  227.         QFree(unknown);
  228.         FreeBitMap(bmptr);
  229.         FreeSprite(sprite);
  230.         return NULL;
  231.           }
  232.       for (i = 0; i < (UInt16)u; i++)
  233.         {
  234.           if ((ReadInt32(file, &x) == FALSE)
  235.           || (x > 32767L)
  236.           || (x < -32768L)
  237.           || (ReadInt32(file, &y) == FALSE)
  238.           || (y > 32767L)
  239.           || (y < -32768L)
  240.           || (ReadInt32(file, &w) == FALSE)
  241.           || (w == 0)
  242.           || (w > (UInt32)(sprite->maxwidth))
  243.           || (ReadInt32(file, &h) == FALSE)
  244.           || (h == 0)
  245.           || (h > (UInt32)(sprite->maxheight))
  246.           || (ReadBytes(file, bmptr->data, w * h) == FALSE))
  247.         {
  248.           QFree(unknown);
  249.           FreeBitMap(bmptr);
  250.           FreeSprite(sprite);
  251.           return NULL;
  252.         }
  253.           bmptr->width = (UInt16)w;
  254.           bmptr->height = (UInt16)h;
  255.           if (i == 0)
  256.         f = AddSpriteImage(sprite, -1, TRUE, unknown[i],
  257.                    (Int16)x, (Int16)y, bmptr);
  258.           else
  259.         f = AddSpriteImage(sprite, f, TRUE, unknown[i],
  260.                    (Int16)x, (Int16)y, bmptr);
  261.         }
  262.       QFree(unknown);
  263.     }
  264.       else
  265.     {
  266.       if ((ReadInt32(file, &x) == FALSE)
  267.           || (x > 32767L)
  268.           || (x < -32768L)
  269.           || (ReadInt32(file, &y) == FALSE)
  270.           || (y > 32767L)
  271.           || (y < -32768L)
  272.           || (ReadInt32(file, &w) == FALSE)
  273.           || (w == 0)
  274.           || (w > (UInt32)(sprite->maxwidth))
  275.           || (ReadInt32(file, &h) == FALSE)
  276.           || (h == 0)
  277.           || (h > (UInt32)(sprite->maxheight))
  278.           || (ReadBytes(file, bmptr->data, w * h) == FALSE))
  279.         {
  280.           FreeBitMap(bmptr);
  281.           FreeSprite(sprite);
  282.           return NULL;
  283.         }
  284.       bmptr->width = (UInt16)w;
  285.       bmptr->height = (UInt16)h;
  286.       AddSpriteImage(sprite, -1, FALSE, 0.0, (Int16)x, (Int16)y, bmptr);
  287.     }
  288.     }
  289.   FreeBitMap(bmptr);
  290.   return sprite;
  291. }
  292.  
  293.  
  294. /*
  295.  * Print the structure of a sprite in "outf".
  296.  */
  297. void DumpSprite(FILE *outf, SpritePtr sprite)
  298. {
  299.   UInt16 n, i;
  300.  
  301.   if (outf == NULL || sprite == NULL)
  302.     return;
  303.   fprintf(outf, "Unknown1 =  0x%lx\n", sprite->unknown1);
  304.   fprintf(outf, "Unknown2 =  0x%lx\n", sprite->unknown2);
  305.   fprintf(outf, "Radius =    %f\n", sprite->radius);
  306.   fprintf(outf, "MaxWidth =  %u\n", sprite->maxwidth);
  307.   fprintf(outf, "MaxHeight = %u\n", sprite->maxheight);
  308.   fprintf(outf, "NumFrames = %u\n", sprite->numframes);
  309.   fprintf(outf, "Unknown4 =  0x%lx\n", sprite->unknown4);
  310.   fprintf(outf, "Unknown5 =  0x%lx\n", sprite->unknown5);
  311.   for (n = 0; n < sprite->numframes; n++)
  312.     {
  313.       printf("Frame %d:\n", n);
  314.       if (sprite->frames[n].numimages == 0)
  315.     {
  316.       fprintf(outf, "   x offset = %d\n",
  317.           sprite->frames[n].images[0].xoffset);
  318.       fprintf(outf, "   y offset = %d\n",
  319.           sprite->frames[n].images[0].yoffset);
  320.       fprintf(outf, "   width =    %u\n",
  321.           sprite->frames[n].images[0].bitmap.width);
  322.       fprintf(outf, "   height =   %u\n",
  323.           sprite->frames[n].images[0].bitmap.height);
  324.     }
  325.       else
  326.     for (i = 0; i < sprite->frames[n].numimages; i++)
  327.       {
  328.         printf("   Image %d:\n", i);
  329.         fprintf(outf, "      unknown  = %f\n",
  330.             sprite->frames[n].unknown[i]);
  331.         fprintf(outf, "      x offset = %d\n",
  332.             sprite->frames[n].images[i].xoffset);
  333.         fprintf(outf, "      y offset = %d\n",
  334.             sprite->frames[n].images[i].yoffset);
  335.         fprintf(outf, "      width =    %u\n",
  336.             sprite->frames[n].images[i].bitmap.width);
  337.         fprintf(outf, "      height =   %u\n",
  338.             sprite->frames[n].images[i].bitmap.height);
  339.       }
  340.     }
  341.   fprintf(outf, "End.\n");
  342. }
  343.  
  344.  
  345. /*
  346.  * Adjust the sprite information according to the width and height
  347.  * of the frames.  This should be called before saving a sprite.
  348.  */
  349. void AdjustSpriteInfo(SpritePtr sprite)
  350. {
  351.   UInt16  n, i;
  352.   Float32 w, h;
  353.   Bool    modified = FALSE;
  354.  
  355.   for (n = 0; n < sprite->numframes; n++)
  356.     if (sprite->frames[n].numimages == 0)
  357.       {
  358.     if (sprite->frames[n].images[0].bitmap.width > sprite->maxwidth)
  359.       {
  360.         sprite->maxwidth = sprite->frames[n].images[0].bitmap.width;
  361.         modified = TRUE;
  362.       }
  363.     if (sprite->frames[n].images[0].bitmap.height > sprite->maxheight)
  364.       {
  365.         sprite->maxheight = sprite->frames[n].images[0].bitmap.height;
  366.         modified = TRUE;
  367.       }
  368.       }
  369.     else
  370.       for (i = 0; i < sprite->frames[n].numimages; i++)
  371.     {
  372.       if (sprite->frames[n].images[i].bitmap.width > sprite->maxwidth)
  373.         {
  374.           sprite->maxwidth = sprite->frames[n].images[i].bitmap.width;
  375.           modified = TRUE;
  376.         }
  377.       if (sprite->frames[n].images[i].bitmap.height > sprite->maxheight)
  378.         {
  379.           sprite->maxheight = sprite->frames[n].images[i].bitmap.height;
  380.           modified = TRUE;
  381.         }
  382.     }
  383.   if (modified == TRUE)
  384.     {
  385.       w = (Float32)(sprite->maxwidth / 2);
  386.       h = (Float32)(sprite->maxheight / 2);
  387. /*!
  388.       sprite->radius = sqrt(w * w + h * h);
  389. */
  390.     }
  391.   /*! I don't know how to adjust the other fields (unknown{1,2,4,5}) */
  392. }
  393.  
  394.  
  395. /*
  396.  * Save sprite to a file (all frames).
  397.  * The number of bytes written is returned (0 if an error occured).
  398.  */
  399. UInt32 SaveSprite(FILE *file, SpritePtr sprite)
  400. {
  401.   UInt16 n, i;
  402.   Int32  x, y;
  403.   UInt32 u, w, h;
  404.   UInt32 size;
  405.  
  406.   if (sprite == NULL)
  407.     return 0L;
  408.   w = (UInt32)(sprite->maxwidth);
  409.   h = (UInt32)(sprite->maxheight);
  410.   u = (UInt32)(sprite->numframes);
  411.   if ((WriteBytes(file, "IDSP", 4) == FALSE)
  412.       || (WriteInt32(file, &(sprite->unknown1)) == FALSE)
  413.       || (WriteInt32(file, &(sprite->unknown2)) == FALSE)
  414.       || (WriteFloat32(file, &(sprite->radius)) == FALSE)
  415.       || (WriteInt32(file, &w) == FALSE)
  416.       || (WriteInt32(file, &h) == FALSE)
  417.       || (WriteInt32(file, &u) == FALSE)
  418.       || (WriteInt32(file, &(sprite->unknown4)) == FALSE)
  419.       || (WriteInt32(file, &(sprite->unknown5)) == FALSE))
  420.     return 0L;
  421.   size = 36L;
  422.   for (n = 0; n < sprite->numframes; n++)
  423.     {
  424.       if (sprite->frames[n].numimages == 0)
  425.     {
  426.       u = 0;
  427.       x = (Int32)(sprite->frames[n].images[0].xoffset);
  428.       y = (Int32)(sprite->frames[n].images[0].yoffset);
  429.       if ((WriteInt32(file, &u) == FALSE)
  430.           || (WriteInt32(file, &x) == FALSE)
  431.           || (WriteInt32(file, &y) == FALSE))
  432.         return 0L;
  433.       u = SaveBitMap(file, &(sprite->frames[n].images[0].bitmap));
  434.       if (u == 0L)
  435.         return 0L;
  436.       size += 12L + u;
  437.     }
  438.       else
  439.     {
  440.       /* hack... */
  441.       if ((sprite->frames[n].numimages >= 2)
  442.           && (sprite->frames[n].unknown[1] > 0.1))
  443.         u = 0x1000000;
  444.       else
  445.         u = 0x0000001;
  446.       if (WriteInt32(file, &u) == FALSE)
  447.         return 0L;
  448.       u = (UInt32)(sprite->frames[n].numimages);
  449.       if (WriteInt32(file, &u) == FALSE)
  450.         return 0L;
  451.       size += 8L;
  452.       for (i = 0; i < sprite->frames[n].numimages; i++)
  453.         if (WriteFloat32(file, &(sprite->frames[n].unknown[i])) == FALSE)
  454.           return 0L;
  455.       for (i = 0; i < sprite->frames[n].numimages; i++)
  456.         {
  457.           x = (Int32)(sprite->frames[n].images[i].xoffset);
  458.           y = (Int32)(sprite->frames[n].images[i].yoffset);
  459.           if ((WriteInt32(file, &x) == FALSE)
  460.           || (WriteInt32(file, &y) == FALSE))
  461.         return 0L;
  462.           u = SaveBitMap(file, &(sprite->frames[n].images[i].bitmap));
  463.           if (u == 0L)
  464.         return 0L;
  465.           size += 12 + u;
  466.         }
  467.     }
  468.     }
  469.   return size;
  470. }
  471.  
  472. /* end of file */
  473.